/*
 * @(#)SessionContainer.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.framework;

import java.io.File;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dcivision.framework.bean.AuditLoginOut;
import com.dcivision.framework.bean.SysFunction;
import com.dcivision.framework.dao.AuditLoginOutDAObject;
import com.dcivision.staff.bean.StaffRecord;
import com.dcivision.staff.dao.StaffRecordDAObject;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.core.PreferenceManager;

/**
  SessionContainer.java

  This class is stored in session and provide all session level functions.

    @author          Rollo Chan
    @company         DCIVision Limited
    @creation date   25/06/2003
    @version         $Revision: 1.60.4.2 $
*/

public class SessionContainer implements HttpSessionBindingListener  {

  public static final String REVISION = "$Revision: 1.60.4.2 $";

  private HttpSession httpSession = null;
  private Timestamp loginTime = null;
  private String ipAddress = null;
  private String loginStatus = null;
  private Locale currentLocale = null;
  private Hashtable hashLastUsedFunction = null;

  //set to by pass all permission checking
  //1. for workflow handling
  private boolean byPassPermission = false;

  protected Log log = LogFactory.getLog(this.getClass().getName());
  protected UserRecord userRecord = null;
  protected StaffRecord staffRecord = null;
  protected ApplicationContainer appContainer = null;
  protected PermissionManager permManager = null;

  public SessionContainer() {
    this.permManager = new PermissionManager(this);
    this.hashLastUsedFunction = new Hashtable();
  }

  public String getSessionID() {
    //*original return null if no session found
    //return this.httpSession == null ? null : this.httpSession.getId();
    return this.httpSession == null ? "" : this.httpSession.getId();
  }

  public void setHttpSession(HttpSession session) {
    this.httpSession = session;
  }

  /**
   * saveLastUsedFunction
   *
   * Save the last used function per module.
   *
   * @param functionCode  The last used function code.
   */
  public void saveLastUsedFunction(String functionCode) {
    if (!Utility.isEmpty(functionCode)) {
      this.hashLastUsedFunction.put(functionCode.substring(0, 3), functionCode);
    }
  }

  /**
   * getLastUsedFunctionURL
   *
   * Get the last used function by the module function code given.
   *
   * @param moduleFunctionCode  Module function code.
   * @return                    Last used function URL.
   */
  public String getLastUsedFunctionURL(String moduleFunctionCode) {
    String lastUsedFucCode = (String)this.hashLastUsedFunction.get(moduleFunctionCode);
    if (!Utility.isEmpty(lastUsedFucCode)) {
      SysFunction lastUsedSysFunc = this.appContainer.getSysFunctionByFunctionCode(lastUsedFucCode);
      if (lastUsedSysFunc != null) {
        return(lastUsedSysFunc.getLinkUrl());
      }
    }
    return(null);
  }

  /**
   * getUserRecord
   *
   * @return The current login User Record object
   */
  public UserRecord getUserRecord() {
    return(this.userRecord);
  }

  /**
   * getStaffRecord
   *
   * @return The current login User Record object
   */
  public StaffRecord getStaffRecord() {
    return(this.staffRecord);
  }

  /**
   * setUserRecord
   *
   * @param userRecord Set the current login User Record object
   */
  public void setUserRecord(UserRecord userRecord) {
    this.userRecord = userRecord;
    if (userRecord != null && UserRecord.USER_TYPE_STAFF.equals(userRecord.getUserType())) {
      Connection conn = null;
      try {
        conn = DataSourceFactory.getConnection();
        StaffRecordDAObject staffRecordDAO = new StaffRecordDAObject(this, conn);
        //ignore the staff record_status(lee.lv in 060411 for bug 4940)
        this.staffRecord = (StaffRecord)staffRecordDAO.getObjectIgnoreStatusByID(userRecord.getUserLinkID());
      } catch (Exception e) {
        log.error("Fail to retrieve staff record of that user", e);
      } finally {
        try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
      }
    }
  }

  /**
   * getUserIPAddresss
   *
   * @return The current login User IP address
   */
  public String getUserIPAddress(){
    return ipAddress;
  }

  /**
   * setUserIPAddress
   *
   * @param ip Set the current login User IP address
   */
  public void setUserIPAddress(String ip){
    ipAddress = ip;
  }

  public String getLoginStatus(){
    return loginStatus;
  }

  public void setLoginStatus(String loginStatus){
    this.loginStatus = loginStatus;
  }

  /**
   * getLoginTime
   *
   * @return  The login time of the current user.
   */
  public Timestamp getLoginTime() {
    return(this.loginTime);
  }

  /**
   * setLoginTime
   *
   * @param inTime  The login time of the user.
   */
  public void setLoginTime(Timestamp inTime) {
    this.loginTime = inTime;
  }

  /**
   * getUserRecordID - Get the current login user record ID.
   *
   * @return Current login user record ID
   */
  public Integer getUserRecordID() {
    if (this.userRecord==null) {
      return(null);
    } else {
      return(this.userRecord.getID());
    }
  }

  /**
   * setLocale
   *
   * @param loc - The current locale of the user.
   */
  public void setLocale(Locale loc) {
    this.currentLocale = loc;
    if (this.httpSession!=null) {
      this.httpSession.setAttribute(org.apache.struts.Globals.LOCALE_KEY, loc);
    }
  }

  /**
   * valueUnbound - The container calls this method when it is being unbound from the session.
   *
   * @param event       The HTTP session binding event
   */
  public void valueUnbound(HttpSessionBindingEvent event) {
    log.info("User Session Expired: " + (this.userRecord==null ? "-1" : this.userRecord.getID().toString()));
    log.info("User Session ID: \""+ event.getSession() == null ? "null" : event.getSession().getId() + "\"");
    
    HttpSession session = event.getSession();
    if (session != null){
    	ApplicationContainer appCon = (ApplicationContainer)session.getServletContext().getAttribute(GlobalConstant.APPLICATION_CONTAINER_KEY);
      appCon.logoutUser(getUserRecordID());
    }

    if (AuditLoginOut.STATUS_LOGIN_SUCCESS.equals(loginStatus)){
      String auditStatus = AuditLoginOut.STATUS_TIMEOUT;
      auditTimeout(auditStatus, "Y", event.getSession().getId());
    }

    //remove sessionCtn to PermissionManager sessionctn listener
    PermissionManager.removePermissionListener(this);        
    
    //* added by Angus. To clean the temporary storage file the user has uploaded for workflow module
    try {
      if (event.getSession()!=null) {
        String path = com.dcivision.upload.web.MaintMultipleFileUploadAction.STORAGE_ROOT + "/" + event.getSession().getId();
        //log.debug("path: "+path);
        File storageFolder = new File(path);
        if (storageFolder.exists() && !path.equals(com.dcivision.upload.web.MaintMultipleFileUploadAction.STORAGE_ROOT + "/") ) {
          File[] fileList = storageFolder.listFiles();
          for (int i=0; fileList!=null && i<fileList.length; i++) {
            //log.debug("deleting file " + fileList[i].getName() + " ..........");
            boolean bDeleted = fileList[i].delete();
          }
          //log.debug("deleteing folder: " + storageFolder.getName());
          storageFolder.delete();
        }
      }
    } catch (Exception ignore) {
    }
  }

  protected void auditTimeout(String status, String timeout, String sessionID) {
    Connection conn = null;
    try {
      conn = DataSourceFactory.getConnection();
      synchronized (conn) {
        AuditLoginOutDAObject auditLoginOutDAObject = new AuditLoginOutDAObject(null, conn);
        AuditLoginOut auditLoginOut = new AuditLoginOut();
        auditLoginOut.setUserRecordID(this.getUserRecordID());
        auditLoginOut.setIPAddress(ipAddress);
        auditLoginOut.setLoginDatetime(loginTime);
        auditLoginOut.setLogoutDatetime(new Timestamp(System.currentTimeMillis()));
        auditLoginOut.setLoginStatus(status);
        auditLoginOut.setTimeoutFlag(timeout);
        auditLoginOut.setSessionID(sessionID);
        auditLoginOutDAObject.updateBySessionID(auditLoginOut);
        conn.commit();
      }
    } catch (Exception e) {
      log.error("Fail to audit logout for id='"+getUserRecordID()+"'"+e.getMessage(), e);
    } finally {
      try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
    }
  }

  /**
   * valueBound - The container calls this method when it is being bound to the session.
   *
   * @param event      The HTTP session binding event
   */
  public void valueBound(HttpSessionBindingEvent event) {
    // Set system default locale.
    this.httpSession = event.getSession();
    this.appContainer = (ApplicationContainer)this.httpSession.getServletContext().getAttribute(GlobalConstant.APPLICATION_CONTAINER_KEY);
//    //add sessionCtn to PermissionManager sessionctn listener
//    PermissionManager.addPermissionListener(this);        
    log.info("User Session ID: \""+ this.httpSession.getId() + "\"");
    log.info("User Session Locale Setted: \""+ this.httpSession.getAttribute(org.apache.struts.Globals.LOCALE_KEY) + "\"");
  }

  /**
   * getPreference - gets the system preference as default, but return individual preference is defined
   *
   * @return String     The customized preference interface
   */
  public String getPreference() {
    String preference = SystemParameterFactory.getSystemParameter(SystemParameterConstant.PREFERENCE);
    if ((this.getUserRecord()!=null) && this.getUserRecord().getPreference()!=null) {
      preference = this.getUserRecord().getPreference().toString();
    }
    return PreferenceManager.getValidPreference(preference).toString();
  }

  /**
   * getSessionLocale - gets the system locale as default, but return individual locale is defined
   *
   * @return Locale    The customized locale
   */
  public Locale getSessionLocale() {
    if (this.httpSession!=null && this.httpSession.getAttribute(org.apache.struts.Globals.LOCALE_KEY)!=null) {
      return ((Locale)this.httpSession.getAttribute(org.apache.struts.Globals.LOCALE_KEY));
    } else {
      String sLoc = SystemParameterFactory.getSystemParameter(SystemParameterConstant.LOCALE);
      return Utility.getLocaleByString(sLoc);
    }
  }

  /**
   * getUserFullName - Get the current login user full name.
   *
   * @return  The user full name of current login user.
   */
  public String getUserFullName() {
    return(this.userRecord!=null ? this.userRecord.getFullName() : null);
  }

  /**
   * getFunctionName - get the function name of the given sysFunction objection
   *
   * @return system function name
   * @param sysFunction the SysFunction Object
   */
  public String getFunctionName(com.dcivision.framework.bean.SysFunction sysFunction) {
    return (this.getFunctionName(sysFunction, this.getSessionLocale().toString()));
  }

  /**
   * getFunctionName - get the function name of the given sysFunction objection,
   *                   under the given locale
   *
   * @return system function name
   * @param sysFunction the SysFunction Object
   * @param sLocaleStr the locale string
   */
  protected String getFunctionName(SysFunction sysFunction, String sLocaleStr) {
    String temp = null;
    if (GlobalConstant.LOCALE_STR_ZH_HK.equals(sLocaleStr)) {
      temp = sysFunction.getFunctionNameZhHk();
      if (Utility.isEmpty(temp)){
        return sysFunction.getFunctionName();
      } else {
        return temp;
      }
    } else if (GlobalConstant.LOCALE_STR_ZH_CN.equals(sLocaleStr)) {
      temp = sysFunction.getFunctionNameZhCn();
      if (Utility.isEmpty(temp)) {
        return sysFunction.getFunctionName();
      } else {
        return temp;
      }
    } else {
      return sysFunction.getFunctionName();
    }
  }

  public String getFunctionNameByFunctionCode(String sFunctionCode) {
    SysFunction sysFunc = this.appContainer.getSysFunctionByFunctionCode(sFunctionCode);
    return(this.getFunctionName(sysFunc, this.getSessionLocale().toString()));
  }

  public String getFunctionNameByFunctionID(Integer nFunctionID) {
    SysFunction sysFunc = this.appContainer.getSysFunctionByFunctionID(nFunctionID);
    return(this.getFunctionName(sysFunc, this.getSessionLocale().toString()));
  }

  public ApplicationContainer getAppContainer() {
    //log.info("appContainer==null?"+(appContainer==null));
    return(this.appContainer);
  }

  public List getAccessibleSystemFunction() {
    if (this.permManager.getMenuItem()==null) {
      log.info("initialize accessible system function list");
      this.permManager.initAccessibleSystemFunction();
    }
    return (this.permManager.getMenuItem());
  }

  public List getAccessibleSystemFunction(Integer parentID) {
    List result = new ArrayList();

    if (this.permManager.getMenuItem()==null) {
      this.permManager.initAccessibleSystemFunction();
    }

    for (int i = 0; i < this.permManager.getMenuItem().size(); i++) {
      SysFunction tmp = (SysFunction)this.permManager.getMenuItem().get(i);
      if (parentID.equals(tmp.getParentID())) {
        result.add(tmp);
      }
    }
    return (result);
  }

  /**
   * hasAccessRight - Check whether has certain access right on given function.
   *
   * @param sFunctionCode   The function code of the function.
   * @param sRight          The access right. e.g. R, I, E
   * @return                Whether has such access right or not.
   */
  public boolean hasAccessRight(String sFunctionCode, String sRight) {
    if(!this.getByPassPermission()){
      return (this.permManager.hasAccessRight(sFunctionCode, sRight));
    }else{
      return true;
    }
  }

  /**
   * getPermissionManager - Get the permission manager of the current session.
   *
   * @return                The permission manager.
   */
  public PermissionManager getPermissionManager() {
    return(this.permManager);
  }



  public boolean getByPassPermission(){
    return this.byPassPermission;
  }

  public void setByPassPermission(boolean byPassPermission){
    this.byPassPermission = byPassPermission ;
  }

//  
//  public void sessionCreated(HttpSessionEvent se) { 
//
//  } 
//
//  public void sessionDestroyed(HttpSessionEvent se) { 
// 
//  } 
  
}